import React, { Component } from "react"
import {
  StyleSheet,
  View,
  Animated,
  Dimensions,
  Text,
  ViewPropTypes as RNViewPropTypes
} from "react-native"

import PropTypes from "prop-types"
// @ts-ignore
const ViewPropTypes = RNViewPropTypes || View.propTypes
export const DURATION = {
  LENGTH_SHORT: 500,
  FOREVER: 0
}

const { height } = Dimensions.get("window")

const styles = StyleSheet.create({
  container: {
    alignItems: "center",
    elevation: 999,
    left: 0,
    position: "absolute",
    right: 0,
    zIndex: 10000
  },
  content: {
    backgroundColor: "black",
    borderRadius: 5,
    padding: 10
  },
  text: {
    color: "white"
  }
})

export interface ToastProps {
  opacity?: any
  fadeInDuration?: any
  style?: any
  textStyle?: any
  positionValue?: any
  position?: any
  fadeOutDuration?: any
  defaultCloseDelay?: any
}
export interface ToastState {
  opacityValue: any
  isShow: boolean
  text: string
}
export default class Toast extends Component<ToastProps, ToastState> {
  duration: number
  callback: any
  animation: any
  isShow: boolean
  timer: any

  constructor(props) {
    super(props)
    this.state = {
      isShow: false,
      text: "",
      opacityValue: new Animated.Value(this.props.opacity)
    }
  }

  show(text, duration, callback) {
    this.duration = typeof duration === "number" ? duration : DURATION.LENGTH_SHORT
    this.callback = callback
    this.setState({
      isShow: true,
      text: text
    })

    this.animation = Animated.timing(this.state.opacityValue, {
      toValue: this.props.opacity,
      duration: this.props.fadeInDuration
    })
    this.animation.start(() => {
      this.isShow = true
      if (duration !== DURATION.FOREVER) this.close()
    })
  }

  close(duration?: any) {
    let delay = typeof duration === "undefined" ? this.duration : duration

    if (delay === DURATION.FOREVER) delay = this.props.defaultCloseDelay || 250

    if (!this.isShow && !this.state.isShow) return
    this.timer && clearTimeout(this.timer)
    this.timer = setTimeout(() => {
      this.animation = Animated.timing(this.state.opacityValue, {
        toValue: 0.0,
        duration: this.props.fadeOutDuration
      })
      this.animation.start(() => {
        this.setState({
          isShow: false
        })
        this.isShow = false
        if (typeof this.callback === "function") {
          this.callback()
        }
      })
    }, delay)
  }

  componentWillUnmount() {
    this.animation && this.animation.stop()
    this.timer && clearTimeout(this.timer)
  }

  render() {
    let pos
    switch (this.props.position) {
      case "top":
        pos = this.props.positionValue
        break
      case "center":
        pos = height / 2
        break
      case "bottom":
        pos = height - this.props.positionValue
        break
    }

    const view = this.state.isShow ? (
      <View style={[styles.container, { top: pos }]} pointerEvents="none">
        <Animated.View
          style={[styles.content, { opacity: this.state.opacityValue }, this.props.style]}
        >
          {React.isValidElement(this.state.text) ? (
            this.state.text
          ) : (
            <Text style={this.props.textStyle}>{this.state.text}</Text>
          )}
        </Animated.View>
      </View>
    ) : null
    return view
  }
}

// @ts-ignore
Toast.propTypes = {
  style: ViewPropTypes.style,
  position: PropTypes.oneOf(["top", "center", "bottom"]),
  // @ts-ignore
  textStyle: Text.propTypes.style,
  positionValue: PropTypes.number,
  fadeInDuration: PropTypes.number,
  fadeOutDuration: PropTypes.number,
  opacity: PropTypes.number
}

// @ts-ignore
Toast.defaultProps = {
  position: "bottom",
  textStyle: styles.text,
  positionValue: 120,
  fadeInDuration: 500,
  fadeOutDuration: 500,
  opacity: 1
}
